package com.app;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.media.CamcorderProfile;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.view.Surface;
import android.view.SurfaceHolder;

import com.app.util.Utils;
import com.app.util.Utils_Log;

import java.io.File;
import java.util.List;

/** 拍照两种方式，1）调用系统到方式；2）自己操控camera来使用Camera对象完成拍照
 *  提供统一的获取摄像头对象的能力；
 * Created by matengfei on 15/8/3.
 */
public class MyCamera {

    private String TAG = MyCamera.class.getSimpleName();


    private Activity activity;
    private int CODE_TAKE_PICTUARE = 1002;
    private String filename = "";
    private File file;


    private Callback callback ;


    public Camera mCamera;
    int numberOfCameras;
    public int mCameraCurrentlyLocked;
    // The first rear facing camera
    int defaultCameraId;
    List<Camera.Size> mSupportedPreviewSizes;


    /*

      private MyCamera(){}

    public static MyCamera getInstance(){
        if()
        return new MyCamera();
    }
    */

    /*
    public void init(Activity activity){
        activity = this.activity;


    }
    */


    public static abstract class Callback {
        public void OnFinal(String filename){};

    }

    public void SetCallback(Callback callback){
        this.callback = callback;
    }



    // 调用系统相机进行拍照
    public void start(Activity activity, String filename ){
        this.activity = activity;
        this.filename = filename;
        // 到系统摄像机
        takePhoto();

    }




    /**
     * 调用系统相机
     */
    private String takePhoto() {

        if(activity.isFinishing())
            return "";

        try {
            file =new File(G.PATH_PIC, filename); //


            Intent takePictureFromCameraIntent = new Intent(
                    MediaStore.ACTION_IMAGE_CAPTURE);

           // if(UserServer.getCameraSetting(activity))
            {
                takePictureFromCameraIntent.putExtra(
                        android.provider.MediaStore.EXTRA_OUTPUT,
                        Uri.fromFile(file));
            }

            activity.startActivityForResult(takePictureFromCameraIntent, CODE_TAKE_PICTUARE);


        } catch (Exception e) {
            e.printStackTrace();
        }


        return file.getAbsolutePath();

    }




    public String OnActivityResult(int requestCode, int resultCode, Intent data) {


        Bitmap img_stream = null;
        String path = "";

        // 图片加载成功
        if (requestCode == CODE_TAKE_PICTUARE && resultCode == Activity.RESULT_OK) { //从拍摄读取

            if( data != null ){
                if(data.getData() != null) {
                    path = getPath(activity, data.getData());
                }
                else{


                    // 低端三星手机不能使用将图片存储到指定位置，将报错；
                    // 保存设置
                    //UserServer.saveCameraSetting(activity, true);

                    ///*
                    Intent takePictureFromCameraIntent = new Intent(
                            MediaStore.ACTION_IMAGE_CAPTURE);
                    takePictureFromCameraIntent.putExtra(
                            android.provider.MediaStore.EXTRA_OUTPUT,
                            Uri.fromFile(file));

                    activity.startActivityForResult(takePictureFromCameraIntent, CODE_TAKE_PICTUARE);
                    //*/

                    //
                    //img_stream = (Bitmap)data.getExtras().get("data");

                }
            }
            else{
                path = file.getPath();

            }
        }
        filename = path;

        if( callback != null) {
            callback.OnFinal(path);

        }

        Utils_Log.e(TAG, "image path: " + path);


        return path;

    }


    public byte[] getContent(){
        if(!filename.isEmpty()){

            byte[] bytes = Utils.readFile2Bytes(filename);
            return bytes;

        }

        return new byte[0];
    }






    int width_camera;
    int height_camera;

    public Camera open(){
        return open(-1,-1);
    }

    public Camera open(int width, int height){

        if( mCamera != null){
            close();
        }

        width_camera = width;
        height_camera = height;

        // Find the total number of cameras available
        numberOfCameras = Camera.getNumberOfCameras();


        // Find the ID of the default camera
        CameraInfo cameraInfo = new CameraInfo();
        for (int i = 0; i < numberOfCameras; i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { // 背后摄像头
                defaultCameraId = i;
            }
        }

        mCameraCurrentlyLocked = defaultCameraId;
        mCamera = Camera.open(mCameraCurrentlyLocked);

        if(width_camera !=-1 && height_camera != -1)
             setParameters();


        Utils_Log.d(TAG, ""+mCamera);
        return mCamera;

    }

    public void close(){
        if(mCamera != null){
            mCamera.lock();
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }



    public boolean Switch(){
        // check for availability of multiple cameras
        if (numberOfCameras == 1) {
            return false;
        }

        // OK, we have multiple cameras.
        // Release this camera -> mCameraCurrentlyLocked
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }

        // Acquire the next camera and request Preview to reconfigure
        // parameters.
        mCamera = Camera
                .open((mCameraCurrentlyLocked + 1) % numberOfCameras);
        mCameraCurrentlyLocked = (mCameraCurrentlyLocked + 1)
                % numberOfCameras;

        if(width_camera !=-1 && height_camera != -1)
            setParameters();

        return true;

    }


    private void setParameters(){
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        Camera.Size size = getOptimalPreviewSize(mSupportedPreviewSizes, width_camera, height_camera);
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(size.width, size.height);
        mCamera.setParameters(parameters);

    }


    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.

        this.width_camera = w;
        this.height_camera = h;

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(w, h);
        mCamera.setParameters(parameters);

    }


    public void SetZoom(int value){
        Camera.Parameters parameter = mCamera.getParameters();
        if(parameter.isZoomSupported()){

            parameter.setZoom( value );
            mCamera.setParameters(parameter);
        }




    }


    public int GetZoom(){
        Camera.Parameters parameter = mCamera.getParameters();
        if(parameter.isZoomSupported()){

            return parameter.getZoom();

        }

        return -1;
    }

    public int GetMaxZoom(){
        Camera.Parameters parameter = mCamera.getParameters();
        if(parameter.isZoomSupported()){

            return parameter.getMaxZoom();

        }

        return -1;
    }


    /**
     * 处理闪光灯
     * @param b
     */
    public void enableSplashLight(boolean b){
        Camera.Parameters parameters = mCamera.getParameters();
        if(b) {
            parameters.setFlashMode(parameters.FLASH_MODE_TORCH); // torch:手电筒
        }
        else{
            parameters.setFlashMode(parameters.FLASH_MODE_OFF);
        }
        mCamera.setParameters(parameters);

    }



    public boolean isFromBackCamera(){
        int cameraCount = 0;
        CameraInfo cameraInfo = new CameraInfo();
        cameraCount = Camera.getNumberOfCameras(); // get cameras number

        for ( int camIdx = 0; camIdx < cameraCount;camIdx++ ) {
            Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
            if ( cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK ) {
                // 代表摄像头的方位，目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
                if(mCameraCurrentlyLocked == camIdx)
                    return true;
            }
        }

        return false;

    }

    //判断前置摄像头是否存在
    private int FindFrontCamera(){
        int cameraCount = 0;
        CameraInfo cameraInfo = new CameraInfo();
        cameraCount = Camera.getNumberOfCameras(); // get cameras number

        for ( int camIdx = 0; camIdx < cameraCount;camIdx++ ) {
            Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
            if ( cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT ) {
                // 代表摄像头的方位，目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
                return camIdx;
            }
        }
        return -1;
    }
    //判断后置摄像头是否存在
    private int FindBackCamera(){
        int cameraCount = 0;
        CameraInfo cameraInfo = new CameraInfo();
        cameraCount = Camera.getNumberOfCameras(); // get cameras number

        for ( int camIdx = 0; camIdx < cameraCount;camIdx++ ) {
            Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
            if ( cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK ) {
                // 代表摄像头的方位，目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
                return camIdx;
            }
        }
        return -1;
    }



    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }



    /**打印支持的previewSizes
     *
     */
    public  void printSupportPreviewSize(){
        Camera.Parameters params = mCamera.getParameters();
        List<Size> previewSizes = params.getSupportedPreviewSizes();
        for(int i=0; i< previewSizes.size(); i++){
            Size size = previewSizes.get(i);
            Utils_Log.i(TAG, "previewSizes:width = " + size.width + " height = " + size.height);
        }

    }

    /**打印支持的pictureSizes
     *
     */
    public  void printSupportPictureSize(){
        Camera.Parameters params = mCamera.getParameters();
        List<Size> pictureSizes = params.getSupportedPictureSizes();
        for(int i=0; i< pictureSizes.size(); i++){
            Size size = pictureSizes.get(i);
            Utils_Log.i(TAG, "pictureSizes:width = " + size.width
                    + " height = " + size.height);
        }
    }
    /**打印支持的聚焦模式
     *
     */
    public void printSupportFocusMode(){
        Camera.Parameters params = mCamera.getParameters();
        List<String> focusModes = params.getSupportedFocusModes();
        for(String mode : focusModes){
            Utils_Log.i(TAG, "focusModes--" + mode);
        }
    }

    /**
     *
     */
    public void printSupportFlashMode(){
        Camera.Parameters params = mCamera.getParameters();
        List<String> modes = params.getSupportedFlashModes();
        for(String mode : modes){
            Utils_Log.i(TAG, "flashmode--" + mode);
        }
    }

    /**
     *
     */
    public void printZoomRatios(){

        Camera.Parameters parameter = mCamera.getParameters();
        if(parameter.isZoomSupported()){

            List<Integer> modes = parameter.getZoomRatios();
            for(Integer mode : modes){
                Utils_Log.i(TAG, "ZoomRatios--" + mode);
            }
        }

    }





    // http://m.blog.csdn.net/blog/long33long/7676653
    private static int getDisplayRotation(Activity activity) {
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .getRotation();
        switch (rotation) {
            case Surface.ROTATION_0: return 0;
            case Surface.ROTATION_90: return 90;
            case Surface.ROTATION_180: return 180;
            case Surface.ROTATION_270: return 270;
        }
        return 0;
    }



    public static void setCameraDisplayOrientation(Activity activity,
                                                   int cameraId, Camera camera) {
        // See android.hardware.Camera.setCameraDisplayOrientation for
        // documentation.
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int degrees = getDisplayRotation(activity);
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }



    //////////////////////////////////////////////////////////////////////////////
    @SuppressLint("NewApi")
    private String getPath(final Context context, final Uri uri) {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }

                // TODO handle non-primary volumes
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[] {
                        split[1]
                };

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {

            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }


    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context The context.
     * @param uri The Uri to query.
     * @param selection (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    private String getDataColumn(Context context, Uri uri, String selection,
                                       String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {
                column
        };

        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                    null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }


    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    public static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri.getAuthority());
    }


////////////////////////////////////////////////////////////////////////////////////


}
